package com.example.concurrent;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class Jmm04_CodeAtomic {
    /**
     * 正确方式（使用synchronized保证并发下的原子性）
     * 解析：
     * 原子性即一个操作一旦开始，便不会被中断，直到操作执行完成
     * 也即解决了上述volatile场景下的并发问题
     */
    static final Object obj = new Object();
    /**
     * 结果错误(尝试添加volatile保证线程间的可见性)
     * 解析：
     * 线程1如果在读取counter后还未修改就消耗完了时间片
     * 被线程2竞争到CPU时间片中断了线程1; 并修改了counter
     * 此时的线程1并不能接收到counter失效的信号，且线程1会被丢掉或者
     * 重新竞争到时间片后线程1用旧值执行➕1操作，将错误的值写回到主存内
     */
//    private volatile static int counter = 0;
    //结果错误
    private static int counter = 0;
    //原子类
//    private static AtomicInteger counter = new AtomicInteger(0);

    //10个线程，每个线程对counter加1000，预期结果为1万；
    public static void main(String[] args) {
        //栅栏屏障，让10个线程全部创建好后，同时执行提高并发度
        CyclicBarrier barrier = new CyclicBarrier(10, new Runnable() {
            @Override
            public void run() {
                System.out.println("10个线程已全部准备就绪");
            }
        });
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                //方法1：使用独占锁
                for (int j = 0; j < 1000; j++) {
                    synchronized (obj) {
                        counter++; //此操作分为读(read)、修改(use)、写回主存(write)三步；这三步并非原子性操作（JMM不保证它们连续执行）
                    }
                }
                //方法2：使用Atomic原子类：AtomicInteger
//                counter.getAndIncrement();
                try {
                    //通知栅栏线程已准备就绪
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
            thread.start();
        }

        //thread.start()方法是异步执行的，此处的休眠是防止线程创建好后（还未执行完）就会被sout
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(counter);
    }
}
